/*
Copyright (C) 1996-1997 GX Media, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "stdafx.h"
#include "Quake.h"

struct dentry_t {
	int offset;
	int size;
};

struct dheader_t {
	int version;
	dentry_t entities;
	dentry_t planes;
	dentry_t miptex;
	// ...who cares about the rest
};

struct miptex_t {
	char name[16];
	int width;
	int height;
	int offset1;
	int offset2;
	int offset4;
	int offset8;
};

struct tex_t {
	char name[16];
	FILE *file;
	int offset;
	miptex_t miptex;
};

int texs = 0;
tex_t *tex;

int count = 0;
int meter = 0;

int pTotal;
bool (*ProgressFunc)(int percent);

// TODO: Add reading error handling.

void readbsp(const wxString &filename, FILE *file, long offset) {

	dheader_t dheader;

	fseek(file, offset, SEEK_SET);
	
	if(fread(&dheader, sizeof(dheader), 1, file) != 1)
	{
		fclose(file);
		return;
	}

	if(dheader.version > 29)
		return;

	int numtex;
	int *texoffset;

	fseek(file, offset + dheader.miptex.offset, SEEK_SET);
	if(fread(&numtex, sizeof(numtex), 1, file) != 1)
	{
		fclose(file);
		return;
	}
	
	texoffset = (int *)malloc(sizeof(int) * numtex);
	if(fread(texoffset, sizeof(int), numtex, file) != numtex)
	{
		fclose(file);
		return;
	}

	for(int i = 0; i < numtex; i++) {
		miptex_t miptex;
		fseek(file, offset + dheader.miptex.offset + texoffset[i], SEEK_SET);
		if(fread(&miptex, sizeof(miptex), 1, file) != 1)
		{
			fclose(file);
			return;
		}

		bool dup = false;
		for(int j = 0; j < texs; j++) {
			if(!strcmpi(tex[j].name, miptex.name)) {
				dup = true;
				break;
			}
		}
		if(dup)
			continue;

		strcpy(tex[texs].name, miptex.name);
		tex[texs].file = file;
		tex[texs].offset = offset + dheader.miptex.offset + texoffset[i];
		tex[texs].miptex = miptex;

		texs++;
	}
}

void readpak(FILE *file) {

	pak_header_t pak_header;
	pak_entry_t *pak_entry;

	if(fread(&pak_header, sizeof(pak_header), 1, file) != 1)
		return;

	pak_entry = (pak_entry_t *)malloc(pak_header.size);

	fseek(file, pak_header.offset, SEEK_SET);
	if(fread(pak_entry, pak_header.size, 1, file) != 1)
		return;

	int t = (int)(pak_header.size / sizeof(pak_entry_t));

	if(count == 0)
//		Dialog_MeterChange(t * 4);
		pTotal = t * 4;
	else
//		Dialog_MeterChange((meter + t) * 2);
		pTotal = (meter + t) * 2;

	count++;

	for(int i = 0; i < t; i++) {
		strlwr(pak_entry[i].filename);
		if(strstr(pak_entry[i].filename, ".bsp") && !strstr(pak_entry[i].filename, "b_")) {
//			Dialog_MeterUpdate(meter + i, "Scanning %s", pak_entry[i].filename);
			ProgressFunc((meter + i) * 100 / pTotal);
			readbsp(wxString(pak_entry[i].filename, wxConvUTF8), file, pak_entry[i].offset);
		}
		else
//			Dialog_MeterUpdate(meter + i, NULL);
			ProgressFunc((meter + i) * 100 / pTotal);
	}

	meter += t;
}

void getpalfrompak(const wxString &pak_filename) {
	FILE *file = fopen(pak_filename.utf8_str(), "rb");

	pak_header_t pak_header;
	pak_entry_t *pak_entry;

	if(fread(&pak_header, sizeof(pak_header), 1, file) != 1)
		return;

	pak_entry = (pak_entry_t *)malloc(pak_header.size);

	fseek(file, pak_header.offset, SEEK_SET);
	if(fread(pak_entry, pak_header.size, 1, file) != 1)
		return;

	int t = (int)(pak_header.size / sizeof(pak_entry_t));

	for(int i = 0; i < t; i++) {
		strlwr(pak_entry[i].filename);
		if(strstr(pak_entry[i].filename, "palette.lmp")) {
			char buf[768];
			fseek(file, pak_entry[i].offset, SEEK_SET);
			if(fread(buf, 768, 1, file) != 1)
			{
				return;
			}

			FILE *pal_file = fopen("palette.lmp", "wb");
			if(fwrite(buf, 768, 1, pal_file) != 1)
			{
				return;
			}
			fclose(pal_file);
		}
	}

	fclose(file);
}

bool paks2wad(const wxString &quake_root, const wxString &wad_output, bool (*ProgFunc)(int p)) {
	ProgressFunc = ProgFunc;

	tex = (tex_t *)malloc(sizeof(tex_t) * 2500);

	wxString quake_dir = quake_root;
	if(quake_dir[quake_dir.size()-1] != wxT('/'))
		quake_dir += wxT("/");

	/*
	if(qoole_game == GAME_QUAKE)
		strcat(quake_dir, "\\id1\\");
	else if(qoole_game == GAME_HEXEN2) {
		strcpy(quake_dir, hexen2_pak);
		char *c = strrchr(quake_dir, '\\');
		if(c)
			*c = 0;
	}
	*/

	wxString pak0 = quake_dir + wxT("/pak0.pak");
	wxString pak1 = quake_dir + wxT("/pak1.pak");

	FILE *pak0_file = fopen(pak0.utf8_str(), "rb");
	FILE *pak1_file = fopen(pak1.utf8_str(), "rb");

	if(!pak0_file && !pak1_file)
		return false;

//	Dialog_Meter(1, "Building %s", wad_output);

	if(pak0_file) readpak(pak0_file);
	if(pak1_file) readpak(pak1_file);

//	Dialog_MeterChange(meter + texs);
	pTotal = meter + texs;

	wad_header_t wad_header;
	strncpy(wad_header.magic, "WAD2", 4);
	wad_header.entries = texs;
	wad_header.offset = sizeof(wad_header);

	wad_entry_t *wad_entry;
	wad_entry = (wad_entry_t *)malloc(sizeof(wad_entry_t) * texs);

	FILE *wad_file = fopen(wad_output.utf8_str(), "wb");

	unsigned char *buf;
	int size;
	int i;

	for(i = 0; i < texs; i++) {
		if(!strlen(tex[i].name))
			continue;

//		Dialog_MeterUpdate(meter + i, "Adding %s", tex[i].name);
		ProgressFunc((meter + i) * 100 / pTotal);

		size = sizeof(miptex_t) + tex[i].miptex.width * tex[i].miptex.height * 85 / 64;

		wad_entry[i].offset = wad_header.offset;
		wad_entry[i].dsize = size;
		wad_entry[i].size = 0;
		wad_entry[i].type = 0x44;
		wad_entry[i].cmprs = 0;
		strcpy(wad_entry[i].name, tex[i].miptex.name);

		fseek(tex[i].file, tex[i].offset, SEEK_SET);
		fseek(wad_file, wad_header.offset, SEEK_SET);

		buf = (unsigned char *)malloc(size);

		if(fread(buf, size, 1, tex[i].file) != 1)
		{
			fclose(tex[i].file);
			return false;
		}

		fwrite(buf, size, 1, wad_file);

		free(buf);

		wad_header.offset += size;

		TRACE(wxT("%s"), wxString(wad_entry[i].name, wxConvUTF8).c_str());
	}

	fseek(wad_file, 0, SEEK_SET);
	fwrite(&wad_header, sizeof(wad_header), 1, wad_file);

	fseek(wad_file, wad_header.offset, SEEK_SET);
	fwrite(wad_entry, sizeof(wad_entry_t), texs, wad_file);

	if(pak0_file) fclose(pak0_file);
	if(pak1_file) fclose(pak1_file);
	fclose(wad_file);

//	Dialog_MeterKill();

	return true;
}
